/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package csm.uttils.generics;

import java.lang.reflect.InvocationTargetException;
import javax.swing.table.AbstractTableModel;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.NoSuchElementException;
import csm.uttils.Operations;


/**
 *
 * @author Carlos S. Moreno
 */
public class GenericTableModel extends AbstractTableModel {

    private String columnas[];
    private Object datos[][];

    public GenericTableModel(String[] cols)
    {
        columnas = cols;
    }

    public GenericTableModel(String[] cols, Object[][] data)
    {
        columnas = cols;
        datos = data;
    }

    public GenericTableModel(Roster list)
    {
        this(list.toArray());
    }

    public GenericTableModel(hashChart table)
    {
        this(table.toArray());
    }

    public GenericTableModel(Object[] array)
    {
        columnas = getColumsNames(array);
        datos = convertToMatix(array);
    }

    private String[] getColumsFromClass(Class clase) throws SecurityException {
        Field[] atributos = clase.getDeclaredFields();
        String[] cols = new String[atributos.length];
        for (int i = 0; i < atributos.length; i++) {
            cols[i] = Operations.capitalize(atributos[i].getName());
        }
        return cols;
    }

    private String[] getColumsNames(Object[] array)
    {
        String cols[] = null;
        try{
            Class clase = getClassFromArray(array);
            cols = getColumsFromClass(clase);
        }
         catch (NoSuchElementException e)
        {
            cols = new String[] {"No","hay","elementos"};
        }
        finally{
            return cols;
        }
    }

    /**
     * Devuelve la clase del primer elemento del array
     * @param array 
     * @return
     */
    private Class getClassFromArray(Object[] array)
    {
        for (int i = 0; i <= array.length; i++)
        {
            if(array[i] != null)return array[i].getClass();
        }
        throw new NoSuchElementException();
    }


    private String[] getColumsNames(Roster list)
    {
        String cols[] = null;
        try{
         Class clase = list.getElementsClass();
            cols = getColumsFromClass(clase);

        }

        catch (NoSuchElementException e)
        {
            cols = new String[] {"No","hay","elementos"};
        }
        finally{
            return cols;
        }
    }//Fin getColumnsNames


    /**
     * Permite tomar un objeto lista por parámetros y detectar los atributos
     * de la clase de los elementos de la misma, y devolver una matris con
     * una cantidad de columnas igual a la cant de atributos, y una fila por
     * elemento de la lista
     * @param list Roster a convertir en matris
     * @return Matris de datos de los atributos de los objetos de la lista
     */
    private Object[][] convertToMatix(Roster list)

    {
        return convertToMatix(list.toArray());
    }

    /**
     * Permite tomar un arreglo por parámetros y detectar los atributos
     * de la clase de los elementos del mismo, y devolver una matris con
     * una cantidad de columnas igual a la cant de atributos, y una fila por
     * elemento almacenado en el array
     * @param array Array a convertir en matris
     * @return Matris de datos de los atributos de los objetos de la lista
     */
    private Object[][] convertToMatix(Object[] array)

    {
        //Field es una clase que representa a un atributo
        Field[] cols ;//Vector con los nombres de los atributos de la clase
        Object[][] data = null;//Futura matriz de datos
        Object elemento;//Variable auxiliar
        //Method es una clase que representa a un método
        Method meth;//Variable que usaremos para obtener el valor de los atributos

        try{
            //Obtengo los nombres de los atributos de la clase
            cols = getClassFromArray(array).getDeclaredFields();
            //Seteo el tamaño de la matris con las columnas y filas
            data = new Object[array.length][cols.length];

            //Comienzo a recorrer el array
            for (int i = 0; i <= array.length; i++)
            {
                if(array[i]!= null){
                elemento = array[i];//Tomo el elemento de la lista

                //Ahora recorro los atributos (columnas) del elemento actual
                for(int j = 0; j < cols.length; j++)
                {
                    try
                    {/*
                      * Bueno:
                      * - 'Operations.capitalize(cols[i].getName()' me devuelve
                      * el nombre del atributo que quiero conocer con su primera
                      * letra en mayuscula. Y, al concatenarle un 'get' al comienzo,
                      * y gracias a las reglas especificadas para programar en equipo,
                      * obtengo el (posible) nombre del método. Por ej.: "getNombre"
                      *
                      * - 'getMethod' devuelve el método de la clase que tenga el
                      * nombre que se corresponda con la cadena pasada por parámetro
                      *
                      * - 'elemento.getClass()' devuelve la clase de la cual quiero
                      * invocar el método
                      *
                      * y, finalmente
                      *
                      * - 'meth.invoke(elemento)' invoca al al método obtenido
                      * anteriormente, en el objeto pasado por parámetro(en este
                      * "elemento").
                      */
                    meth = (elemento.getClass()).getMethod("get"+ Operations.capitalize(cols[j].getName()));
                    data[i][j] = meth.invoke(elemento);
                    }
                    catch (NoSuchMethodException e){System.out.print(e.toString());}
                    catch (NoSuchMethodError e){System.out.print(e.toString());}

                }//Fin de recorrido de atributos
                }

            }//Fin de recorrido del array

        }
        catch (NullPointerException e){System.out.print("No hay elementos en la tabla");}
        catch (IllegalAccessException e){System.out.print(e.toString());}
        catch (IllegalArgumentException e){System.out.print(e.toString());}
        catch (InvocationTargetException e){System.out.print(e.toString());}
        catch (NoSuchElementException e){
            System.out.print(e.toString());
            data = new Object[0][0];
        }
        finally
        {
            return data;
        }


    }


    public int getRowCount() {
        if (null == datos) return 0;
        return datos.length;
    }

    public int getColumnCount() {
        if (null == datos) columnas = new String[] {"No","hay","elementos"};
        return columnas.length;
    }

    public String getColumnName(int col) {
        return columnas[col];
    }

    public Object getValueAt(int row, int col) {
        return datos[row][col];
    }



}
